package handax.controller;

import handax.GUI.RestaurantTableModel;
import java.sql.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.ArrayList;
import handax.entities.*;
import java.util.Arrays;
import java.util.List;
import javax.swing.*;

/**
 *
 * @author Andreas Apostolidis
 * Κλάση DBManager για την επικοινωνία με τη βάση δεδομένων
 */
public class DBManager {

    private String database = "handax";
    private String user = "nbuser";
    private String password = "nbuser";
    private String driver = "org.apache.derby.jdbc.ClientDriver";
    //private String connString = "jdbc:derby:";
    private String connString = "jdbc:derby://localhost:1527/";
    private Connection dBconnection;
    private Statement statement;
    // Ερωτήματα διαχείρισης περιοχών (ανάκτηση)
    private PreparedStatement selectArea;
    private PreparedStatement selectArea2;
    // Ερωτήματα διαχείρισης κατηγοριών (ανάκτηση)
    private PreparedStatement selectCategory;
    private PreparedStatement selectCategory2;
    // Ερωτήματα διαχείρισης τιμών (ανάκτηση)
    private PreparedStatement selectPrice;
    private PreparedStatement selectPrice2;
    // Ερωτήματα διαχείρισης χρηστών (ανάκτηση)
    private PreparedStatement selectUser;
    private PreparedStatement selectUsers;
    // Ερωτήματα διαχείρισης εστιατορίου (εισαγωγή, ενημέρωση, ανάκτηση, αφαίρεση)
    private PreparedStatement insertRestaurant;
    private PreparedStatement updateRestaurant;
    private PreparedStatement selectRestaurant1;
    private PreparedStatement selectRestaurant2;
    private PreparedStatement selectRestaurant3;
    private PreparedStatement searchRestaurant;
    private PreparedStatement removeRestaurant;
    // Ερωτήματα αξιολόγησης εστιατορίων (εισαγωγή, ανακτηση)
    private PreparedStatement insertRating;
    private PreparedStatement updateRating;
    private PreparedStatement selectRating1;
    private PreparedStatement selectRating2;
    private PreparedStatement selectRating3;
    //Ερωτήματα κρατήσεων εστιατορίου (εισαγωγή, ,ενημέρωση, ανακτηση)
    private PreparedStatement insertReservation;
    private PreparedStatement updateReservation;
    private PreparedStatement selectReservation1;
    private PreparedStatement selectReservation2;
    private PreparedStatement retrieveAllReservations;
    private PreparedStatement removeReservation;
    //μεταβλητή χρησιμοποιείτε για  τον ελεγχο της σύνδεσης με την βάση
    public boolean connectedToDatabase = false;

    /**
     * Δημιουργός της DBManager. Αρχικοποιεί την επικοινωνία με τη βάση δεδομένων και
     * προτετοιμάζει τα απαιτούμενα ερωτήματα.
     */
    public DBManager() {
        try {
            // Φόρτωση της κλάσης του οδηγού της βάσης δεδομένων
            Class.forName(driver);
            // Σύνδεση με τη βάση δεδομένων
            dBconnection = DriverManager.getConnection(connString + database, user, password);            
            statement = dBconnection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
            //ενημέρωση κατάστασης σύνδεσης βάσης δεδομένων
            connectedToDatabase = true;

            // Επιλογή όλων των περιοχών από τη βάση
            selectArea = dBconnection.prepareStatement("SELECT * FROM APP.AREA");
            // Επιλογή περιοχής από τη βάση
            selectArea2 = dBconnection.prepareStatement("SELECT * FROM APP.AREA WHERE ID = ?");
            // Επιλογή όλων των κατηγοριών από τη βάση
            selectCategory = dBconnection.prepareStatement("SELECT * FROM APP.CATEGORY");
            // Επιλογή μιας κατηγορίας από τη βάση
            selectCategory2 = dBconnection.prepareStatement("SELECT * FROM APP.CATEGORY WHERE ID = ?");
            // Επιλογή όλων των τιμών από τη βάση
            selectPrice = dBconnection.prepareStatement("SELECT * FROM APP.PRICE");
            // Επιλογή μιας τιμής από τη βάση
            selectPrice2 = dBconnection.prepareStatement("SELECT * FROM APP.PRICE WHERE ID = ?");
            // Επιλογή χρήστη από τη βάση
            selectUser = dBconnection.prepareStatement("SELECT * FROM APP.USERS WHERE USERNAME=?");
            // Επιλογή όλων των χρήστών από τη βάση
            selectUsers = dBconnection.prepareStatement("SELECT * FROM APP.USERS WHERE ISADMIN = 0");
            //Ενημέρωση στοιχείων εστιατορίου
            updateRestaurant = dBconnection.prepareStatement("UPDATE APP.RESTAURANT SET REST_NAME=?, ADDRESS=?, AREA_ID=?, PHONE=?, CATEGORY_ID=?, INFO=?, DESCR=?, PRICE_ID=?, PHOTO=?  WHERE ID=?");
            // Επιλογή εστιατορίου από την βάση(αναζήτηση με όνομα ,περιοχή,κατηγορία,εύρος τιμών)
            selectRestaurant1 = dBconnection.prepareStatement("SELECT * FROM APP.RESTAURANT WHERE REST_NAME=? AND AREA_ID=? AND CATEGORY_ID=? AND PRICE_ID=?");
//            //Αναζήτηση εστιατορίου
//            searchRestaurant = dBconnection.prepareStatement("SELECT APP.RESTAURANT.REST_NAME,APP.RESTAURANT.ADDRESS,APP.RESTAURANT.AREA_ID,APP.RESTAURANT.PHONE,APP.RESTAURANT.CATEGORY_ID FROM APP.RESTAURANT");
            // Επιλογή εστιατορίου από την βάση(αναζήτηση με κωδικό)
            selectRestaurant2 = dBconnection.prepareStatement("SELECT * FROM APP.RESTAURANT WHERE ID = ?");
            //Επιλογή όλων των εστιατορίων
            selectRestaurant3 = dBconnection.prepareStatement("SELECT * FROM APP.RESTAURANT");
            // Διαγραφή εστιατορίου από την βάση
            removeRestaurant = dBconnection.prepareStatement("DELETE FROM APP.RESTAURANT WHERE ID=?");
            //Εισαγωγή Εστιατορίου
            insertRating = dBconnection.prepareStatement("INSERT INTO APP.RATING (REST_ID, USERNAME, QUALITY, PRICE, SERVICE_TIME, AVERAGE_RATING) VALUES (?,?,?,?,?,?)");
            //Ενημέρωση Κρατήσεων εστιατορίου
            updateRating = dBconnection.prepareStatement("UPDATE APP.RATING SET QUALITY=?, PRICE=?,SERVICE_TIME=?,AVERAGE_RATING=? WHERE REST_ID=? AND USERNAME=?");
            //Επιλογή Αξιολογήσης εστιατορίου
            selectRating1 = dBconnection.prepareStatement("SELECT * FROM APP.RATING WHERE REST_ID=? AND USERNAME=?");
            //Εύρεση μεσου όρου αξιολογήσεων για κάθε εστιατόριο
            selectRating2 = dBconnection.prepareStatement("SELECT AVG(APP.RATING.QUALITY),AVG(APP.RATING.PRICE),AVG(APP.RATING.SERVICE_TIME),AVG(APP.RATING.AVERAGE_RATING) FROM APP.RATING WHERE APP.RATING.REST_ID = ?");
            //Εύρεση  αξιολογήσης 
            selectRating3 = dBconnection.prepareStatement("SELECT APP.RATING.QUALITY , APP.RATING.PRICE , APP.RATING.SERVICE_TIME, APP.RATING.AVERAGE_RATING FROM APP.RATING WHERE APP.RATING.REST_ID = ? AND APP.RATING.USERNAME = ?");
            //Εισαγωγή Κράτησης εστιατορίου
            insertReservation = dBconnection.prepareStatement("INSERT INTO APP.RESERVATION (REST_ID, USERNAME, RESERV_DATE, STATUS_ID) VALUES (?,?,?,?)");
            //Ενημέρωση Κρατήσεων εστιατορίου
            updateReservation = dBconnection.prepareStatement("UPDATE APP.RESERVATION SET RESERV_DATE=?, STATUS_ID=? WHERE REST_ID=? AND USERNAME=?");
            //Επιλογή κράτησης εστιατορίου (με βάση το εστιατόριο και τον χρήστη)
            selectReservation1 = dBconnection.prepareStatement("SELECT * FROM APP.RESERVATION WHERE REST_ID=? AND USERNAME=?");
            //Επιλογή κράτησης εστιατορίου (με βάση την κατάσταση της κράτησης)
            selectReservation2 = dBconnection.prepareStatement("SELECT * FROM APP.RESERVATION WHERE STATUS_ID=?");
            //Ανάκτηση όλων των κρατήσεων
            retrieveAllReservations = dBconnection.prepareStatement("SELECT APP.RESERVATION.REST_ID, APP.RESERVATION.USERNAME, APP.RESTAURANT.REST_NAME, APP.RESERVATION.RESERV_DATE, APP.RESERVATION.STATUS_ID FROM APP.RESERVATION, APP.RESTAURANT WHERE APP.RESERVATION.REST_ID = APP.RESTAURANT.ID");
            //Διαγραφή επιβεβαιωμένων κρατήσεων
            removeReservation = dBconnection.prepareStatement("DELETE FROM APP.RESERVATION WHERE REST_ID=? AND USERNAME=?");
                        
        } catch (Exception exc) {
            System.out.println(exc);
        }
    }

    /**
     * Ανάκτηση των διαθέσιμων περιοχών 
     * @return Επιστρέφει μια λίστα με τις διαθέσιμες περιοχές
     */
    public ArrayList retrieveAreas() {
        try {
            ResultSet rs = selectArea.executeQuery();
            ArrayList<Area> availableArea = new ArrayList<Area>();
            while (rs.next()) {
                Area a = new Area();
                a.setId(rs.getInt("ID"));
                a.setDescr(rs.getString("DESCR"));
                availableArea.add(a);
            }
            return availableArea;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     * Ανάκτηση της διαθέσιμης περιοχης 
     * @param  id Τον κωδικό της περιοχής
     * @return Επιστρέφει ένα αντικείμενο τύπου Area (την περιοχη που ψανουμε)
     */
    public Area retrieveArea(int id) {
        try {
            selectArea2.setInt(1, id);
            ResultSet rs = selectArea2.executeQuery();
            Area a = new Area();
            while (rs.next()) {
                a.setId(rs.getInt("ID"));
                a.setDescr(rs.getString("DESCR"));
            }
            return a;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     * Ανάκτηση των διαθέσιμων κατηγοριών 
     * @return Επιστρέφει μια λίστα με τις διαθέσιμες κατηγορίες
     */
    public List<Category> retrieveCategories() {
        try {
            ResultSet rs = selectCategory.executeQuery();
            ArrayList<Category> availableCategory = new ArrayList<Category>();
            while (rs.next()) {
                Category c = new Category();
                c.setId(rs.getInt("ID"));
                c.setDescr(rs.getString("DESCR"));
                availableCategory.add(c);
            }
            return availableCategory;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     * Ανάκτηση της διαθέσιμης κατηγοριάς
     * @param id Τον κωδικό της κατηγορίας
     * @return Επιστρέφει ένα αντικέιμενο τύπου Category (την κατηγορία που ψάχνουμε)
     */
    public Category retrieveCategory(int id) {
        try {
            selectCategory2.setInt(1, id);
            ResultSet rs = selectCategory2.executeQuery();
            Category c = new Category();
            while (rs.next()) {
                c.setId(rs.getInt("ID"));
                c.setDescr(rs.getString("DESCR"));
            }
            return c;
        } catch (SQLException ex) {
            JOptionPane.showMessageDialog(new JFrame(), ex.getMessage());
            return null;
        }
    }

    /**
     * Ανάκτηση των διαθέσιμων τιμών
     * @return Επιστρέφει μια λίστα με τις διαθέσιμες τιμές
     */
    public ArrayList retrievePrices() {
        try {
            ResultSet rs = selectPrice.executeQuery();
            ArrayList<Price> availablePrice = new ArrayList<Price>();
            while (rs.next()) {
                Price p = new Price();
                p.setId(rs.getInt("ID"));
                p.setDescr(rs.getString("DESCR"));
                availablePrice.add(p);
            }
            return availablePrice;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     * Ανάκτηση της διαθέσιμης τιμης
     * @param  id ΤΟν κωδικό της τιμής
     * @return Επιστρέφει ένα αντικείμενο τύπου Price (την τιμή που ψάχνουμε)
     */
    public Price retrievePrices(int id) {
        try {
            selectPrice2.setInt(1, id);
            ResultSet rs = selectPrice2.executeQuery();
            rs.next();
            Price p = new Price();
            p.setId(rs.getInt("ID"));
            p.setDescr(rs.getString("DESCR"));
            return p;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     * Ανάκτηση χρήστη
     * @param  username Το username του χρήστη
     * @return Επιστρέφει ένα αντικείμενο τύπου User (τον χρήστη που ψάχουμε)
     */
    public User retrieveUser(String username) {
        try {
            selectUser.setString(1, username);
            ResultSet rs = selectUser.executeQuery();
            User u = new User();
            while (rs.next()) {
                u.setUsername(rs.getString("USERNAME"));
                u.setPassword(rs.getString("PASSWORD"));
                u.setIsadmin(rs.getInt("ISADMIN"));
            }
            return u;
        } catch (SQLException ex) {
            JOptionPane.showMessageDialog(new JFrame(), ex.getMessage());
            return null;
        }
    }

    /**
     * Ανάκτηση όλων των χρήστών
     * @return Επιστρέφει όλους τους χρήστες 
     */
    public ArrayList<User> retrieveAllUsers() {
        try {
            ResultSet rs = selectUsers.executeQuery();
            ArrayList<User> users = new ArrayList<User>();

            while (rs.next()) {
                User u = new User();
                u.setUsername(rs.getString("USERNAME"));
                u.setPassword(rs.getString("PASSWORD"));
                u.setIsadmin(rs.getInt("ISADMIN"));
                users.add(u);
            }
            return users;
        } catch (SQLException ex) {
            JOptionPane.showMessageDialog(new JFrame(), ex.getMessage());
            return null;
        }
    }

    /**
     * Αποθήκευση στη βάση ενός εστιατορίου
     * @param rest Το εστιατόριο που θα αποθηκευτεί
     * @return Το ID του εστιατορίου που καταχωρήθηκε ή -1 αν η καταχώρηση δεν πραγματοποιήθηκε
     */
    public int storeRestaurant(Restaurant rest) {
        try {
            int[] autoCol = new int[1];
            autoCol[0] = 1;
            // Εισαγωγή στοιχείων εστιατορίου
            insertRestaurant = dBconnection.prepareStatement("INSERT INTO APP.RESTAURANT (REST_NAME, ADDRESS, AREA_ID, PHONE, CATEGORY_ID, INFO, DESCR, PRICE_ID, PHOTO) VALUES (?,?,?,?,?,?,?,?,?)", autoCol);

            insertRestaurant.setString(1, rest.getRestName());
            insertRestaurant.setString(2, rest.getAddress());
            insertRestaurant.setInt(3, rest.getArea());
            insertRestaurant.setString(4, rest.getPhone());
            insertRestaurant.setInt(5, rest.getCategory());
            insertRestaurant.setString(6, rest.getInfo());
            insertRestaurant.setString(7, rest.getDescr());
            insertRestaurant.setInt(8, rest.getPrice());
            insertRestaurant.setString(9, rest.getPhoto());
            insertRestaurant.executeUpdate();
            ResultSet rs = insertRestaurant.getGeneratedKeys();
            if (rs != null) {
                rs.next();
                int storedID = rs.getInt(1);
                return storedID;
            }
            return -1;
        } catch (SQLException ex) {
            JOptionPane.showMessageDialog(new JFrame(), ex.getMessage());
            return -1;
        }
    }

    /**
     * Ενημέρωση των στοιχείων ενός εστιατορίου
     * @param rest Το αντικείμενο που περιέχει τα νέα στοιχεία του εστιατορίου, το οποίο θα ενημερώσει
     * την αντίστοιχη εγγραφή στη βάση με το ίδιο ID.
     */
    public void updateRestaurant(Restaurant rest) {
        try {
            updateRestaurant.setString(1, rest.getRestName());
            updateRestaurant.setString(2, rest.getAddress());
            updateRestaurant.setInt(3, rest.getArea());
            updateRestaurant.setString(4, rest.getPhone());
            updateRestaurant.setInt(5, rest.getCategory());
            updateRestaurant.setString(6, rest.getInfo());
            updateRestaurant.setString(7, rest.getDescr());
            updateRestaurant.setInt(8, rest.getPrice());
            updateRestaurant.setString(9, rest.getPhoto());
            updateRestaurant.setInt(10, rest.getId());
            updateRestaurant.executeUpdate();
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Διαγραφή εστιατορίου από τη βάση
     * @param rest Το εστιατόριο που θα διαγραφεί
     */
    public void removeRestaurant(Restaurant rest) {
        try {
            removeRestaurant.setInt(1, rest.getId());
            removeRestaurant.executeUpdate();
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Ανάκτηση εστιατορίων 
     * @param sqlstatement,params
     * @return Λίστα με αντικείμενα Restaurant
     */
    public ArrayList retrieveRestaurantFromSearch(String sqlstatement, List<Object> params) {

        try {
            searchRestaurant = dBconnection.prepareStatement(sqlstatement);
            int i = 1;
            for (Object param : params) {
                searchRestaurant.setObject(i, param);
                i++;
            }

            ResultSet rs = searchRestaurant.executeQuery();
            ArrayList<RestaurantTableModel> availableRestaurants = new ArrayList<RestaurantTableModel>();
            while (rs.next()) {
                RestaurantTableModel r = new RestaurantTableModel();
                r.setId(rs.getInt("ID"));
                r.setName(rs.getString("REST_NAME"));
                r.setAddress(rs.getString("ADDRESS"));
                r.setArea(rs.getString("AREA"));
                r.setPhone(rs.getString("PHONE"));
                r.setCategory(rs.getString("CATEGORY"));
                availableRestaurants.add(r);
            }
            return availableRestaurants;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     * Ανάκτηση εστιατορίων με βάση το κρητήριο κωδικός
     * @param id τον κωδικό του εστιατορίου
     * @return Λίστα με αντικείμενα Restaurant
     */
    public Restaurant retrieveRestaurantForView(int id) {
        try {
            selectRestaurant2.setInt(1, id);
            ResultSet rs = selectRestaurant2.executeQuery();
            Restaurant r = new Restaurant();
            while (rs.next()) {
                r.setId(rs.getInt("ID"));
                r.setAddress(rs.getString("ADDRESS"));
                r.setRestName(rs.getString("REST_NAME"));
                r.setArea(rs.getInt("AREA_ID"));
                r.setPhone(rs.getString("PHONE"));
                r.setCategory(rs.getInt("CATEGORY_ID"));
                r.setInfo(rs.getString("INFO"));
                r.setDescr(rs.getString("DESCR"));
                r.setPrice(rs.getInt("PRICE_ID"));
                r.setPhoto(rs.getString("PHOTO"));
            }
            return r;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    public int[] retrieveAllRestId() {
        try {
            ResultSet rs = selectRestaurant3.executeQuery();
            int[] arrayRestsId = new int[100];
            while (rs.next()) {
                Arrays.fill(arrayRestsId, rs.getInt("ID"));
            }
            return arrayRestsId;
        } catch (SQLException ex) {
            JOptionPane.showMessageDialog(new JFrame(), ex.getMessage());
            return null;
        }
    }

    /**
     * Ανάκτηση πίνακα με αναφορές τύπου Restaurant
     * με όλα τα εστιατόρια
     * @return ArrayList<Restaurant>
     */
    public ArrayList<Restaurant> retrieveAllRests() {
        try {
            ResultSet rs = selectRestaurant3.executeQuery();
            ArrayList rests = new ArrayList<Restaurant>();
            while (rs.next()) {
                Restaurant r = new Restaurant();
                r.setId(rs.getInt("ID"));
                r.setAddress(rs.getString("ADDRESS"));
                r.setRestName(rs.getString("REST_NAME"));
                r.setArea(rs.getInt("AREA_ID"));
                r.setPhone(rs.getString("PHONE"));
                r.setCategory(rs.getInt("CATEGORY_ID"));
                r.setInfo(rs.getString("INFO"));
                r.setDescr(rs.getString("DESCR"));
                r.setPrice(rs.getInt("PRICE_ID"));
                r.setPhoto(rs.getString("PHOTO"));
                rests.add(r);
            }
            return rests;
        } catch (SQLException ex) {
            JOptionPane.showMessageDialog(new JFrame(), ex.getMessage());
            return null;
        }
    }

    /**
     * Αποθήκευση στη βάση μιας αξιολόγηησς
     * @param rate Η αξιολόγηση  που θα αποθηκευτεί
     * @return Το 1 αν η αξιολόγηση αποθηκεύτηκε ή -1 αν η καταχώρηση δεν πραγματοποιήθηκε
     */
    public int storeRating(Rating rate) {
        try {

            insertRating.setInt(1, rate.getRestId());
            insertRating.setString(2, rate.getUsername());
            insertRating.setFloat(3, rate.getQuality());
            insertRating.setFloat(4, rate.getPrice());
            insertRating.setFloat(5, rate.getServiceTime());
            insertRating.setFloat(6, rate.getAverageRating());
            insertRating.executeUpdate();
            return 1;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return -1;
        }
    }

    /**
     * Έλεγχος για αν ο χρήστης έχει κάνει αξιολόγηση γι αυτό το εστιατόριο
     * @param id,username ( κωδικός εστιατορίου και username )
     * @return Λίστα με αντικείμενα Rating
     */
    public boolean checkIfRatingExist(int id, String username) {
        try {
            selectRating1.setInt(1, id);
            selectRating1.setString(2, username);
            ResultSet rs = selectRating1.executeQuery();
            rs.next();
            if (rs.getRow() == 0) {
                return false;
            }
            return true;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return true;
        }
    }

    /**
     * Ενημέρωση των στοιχείων μιας αξιολόγησης
     * @param rate Το αντικείμενο που περιέχει τα νέα στοιχεία της αξιολόγησης, το οποίο θα ενημερώσει
     * την αντίστοιχη εγγραφή στη βάση με το ίδιο rest_id και username.
     */
    public int updateRating(Rating rate) {
        try {
            updateRating.setFloat(1, rate.getQuality());
            updateRating.setFloat(2, rate.getPrice());
            updateRating.setFloat(3, rate.getServiceTime());
            updateRating.setFloat(4, rate.getAverageRating());
            updateRating.setInt(5, rate.getRestId());
            updateRating.setString(6, rate.getUsername());
            updateRating.executeUpdate();
            return 1;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return -1;
        }
    }

    /**
     * Ανάκτηση  αξιολόγησης 
     * @param id ( κωδικός εστιατορίου)
     * @return Ένα αντικείμενο Rating που περιέχει τους μέσους όρους στις κατηγορίες αξιολόγησης
     */
    public Rating retrieveRating(int id, String username) {

        try {
            selectRating3.setInt(1, id);
            selectRating3.setString(2, username);
            ResultSet rs = selectRating3.executeQuery();
            rs.next();
            Rating r = new Rating();
            r.setQuality(rs.getInt("QUALITY"));
            r.setPrice(rs.getInt("PRICE"));
            r.setServiceTime(rs.getInt("SERVICE_TIME"));
            r.setAverageRating(rs.getFloat("AVERAGE_RATING"));
            return r;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     * Ανάκτηση μέσων όρων αξιολόγησης 
     * @param id ( κωδικός εστιατορίου)
     * @return Ένα αντικείμενο Rating που περιέχει τους μέσους όρους στις κατηγορίες αξιολόγησης
     */
    public Rating retrieveAvgRating(int id) {

        try {
            selectRating2.setInt(1, id);
            ResultSet rs = selectRating2.executeQuery();
            rs.next();
            Rating avgr = new Rating();
            avgr.setQuality(rs.getFloat(1));
            avgr.setPrice(rs.getFloat(2));
            avgr.setServiceTime(rs.getFloat(3));
            avgr.setAverageRating(rs.getFloat(4));
            return avgr;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     * Αποθήκευση στη βάση μιας αξιολόγηησς
     * @param rate Η αξιολόγηση  που θα αποθηκευτεί
     * @return Το 1 αν η αξιολόγηση αποθηκεύτηκε ή -1 αν η καταχώρηση δεν πραγματοποιήθηκε
     */
    public int storeReservation(Reservation reserv) {
        try {

            insertReservation.setInt(1, reserv.getRestId());
            insertReservation.setString(2, reserv.getUsername());
            insertReservation.setTimestamp(3, new Timestamp(reserv.getReservDate().getTime()));
            insertReservation.setInt(4, reserv.getStatusId());
            insertReservation.executeUpdate();
            return 1;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return -1;
        }
    }

    /**
     * Ενημέρωση των στοιχείων μιας κράτησης
     * @param reserv Το αντικείμενο που περιέχει τα νέα στοιχεία της κράτησης, το οποίο θα ενημερώσει
     * την αντίστοιχη εγγραφή στη βάση με το ίδιο rest_id και username.
     */
    public void updateReservation(Reservation reserv) {
        try {
            updateReservation.setTimestamp(1, new Timestamp(reserv.getReservDate().getTime()));
            updateRestaurant.setInt(2, reserv.getStatusId());
            updateRestaurant.setInt(3, reserv.getRestId());
            updateRestaurant.setString(4, reserv.getUsername());
            updateRestaurant.executeUpdate();
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Ανάκτηση όλων των κρατήσεων 
     * @return μία λίστα με όλα τις κρατήσεις
     */
    public List<Reservation> retrieveAllRerervations() {

        List<Reservation> reserv = new ArrayList<Reservation>();

        try {
            ResultSet rs = retrieveAllReservations.executeQuery();
            while (rs.next()) {
                Reservation r = new Reservation();
                r.setRestId(rs.getInt("REST_ID"));
                r.setRestName(rs.getString("REST_NAME"));
                r.setUsername(rs.getString("USERNAME"));
                r.setReservDate(rs.getTimestamp("RESERV_DATE"));
                r.setStatusId(rs.getShort("STATUS_ID"));
                reserv.add(r);
            }
            return reserv;

        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     * Ανάκτηση κράτησης 
     * @param id,username ( κωδικός εστιατορίου και username )
     * @return ένα αντικείμενο τύπου Reservation( την κράτηση που ψάχνουμε)
     */
    public Reservation retrieveRerervation(int id, String username) {
        try {
            selectReservation1.setInt(1, id);
            selectReservation1.setString(2, username);
            ResultSet rs = selectReservation1.executeQuery();
            if (rs.next()) {
                Reservation r = new Reservation();
                r.setRestId(rs.getInt("REST_ID"));
                r.setUsername(rs.getString("USERNAME"));
                r.setReservDate(rs.getTimestamp("RESERV_DATE"));
                r.setStatusId(rs.getShort("STATUS_ID"));
                return r;
            }
            return null;

        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     * Έλεγχος αν υπάρχει αυτή η κράτηση
     * @param id,username ( κωδικός εστιατορίου και username )
     * @return true αν υπάρχει και false αν δεν υπάρχει
     */
    public Boolean checkIfRerervationExist(int id, String username) {
        try {
            selectReservation1.setInt(1, id);
            selectReservation1.setString(2, username);
            ResultSet rs = selectReservation1.executeQuery();
            rs.next();
            if (rs.getRow() == 0) {
                return false;
            }
            return true;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     * Ανάκτηση κράτησης 
     * @param status_id ( κατάσταση κράτησης )
     * @return μια Λίστα με αντικείμενα Reservation( τις κρατήσεις που ψάχνουμε με την συγκεκριμένη κατάσταση)
     */
    public ArrayList retrieveReservationWithStatus(short status_id) {
        try {
            selectReservation2.setShort(1, status_id);
            ResultSet rs = selectReservation2.executeQuery();
            ArrayList<Reservation> availableReservations = new ArrayList<Reservation>();
            while (rs.next()) {
                Reservation r = new Reservation();
                r.setRestId(rs.getInt("REST_ID"));
                r.setUsername(rs.getString("USERNAME"));
                r.setReservDate(rs.getTimestamp("RESERV_DATE"));
                r.setStatusId(rs.getShort("STATUS_ID"));
                availableReservations.add(r);
            }
            return availableReservations;
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     * Διαγραφή επιβεβαιωμένης κράτησης  από τη βάση
     * @param reserv Η κράτηση που θα διαγραφεί
     */
    public void removeReservation(Reservation reserv) {
        try {
            removeReservation.setInt(1, reserv.getRestId());
            removeReservation.setString(2, reserv.getUsername());
            removeReservation.executeUpdate();
        } catch (SQLException ex) {
            Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
